package com.ng.common.timer;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.StrKit;
import com.ng.biz.model.domain.DataLog;
import com.ng.biz.model.domain.DataTask;
import com.ng.biz.model.domain.HttpApi;
import com.ng.biz.service.IDataLog;
import com.ng.biz.service.IDataTask;
import com.ng.biz.service.IHttpApi;
import com.ng.common.model.response.R;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class DataTaskTimer {
    
    @Autowired
    private IDataTask dataTaskService;
    
    @Autowired
    private IHttpApi httpApiService;
    
    @Autowired
    private IDataLog dataLogService;
    
    
    // 调度器线程池
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
    
    // 任务调度映射
    private final Map<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
    
    // 任务执行状态映射
    private final Map<String, Boolean> taskExecutionStatus = new ConcurrentHashMap<>();
    
    
    public boolean isRunning(String taskId) {
    	return scheduledTasks.containsKey(taskId) ;
    }
    
    /**
     * 检查任务是否正在执行
     */
    private boolean isTaskExecuting(String taskId) {
        return Boolean.TRUE.equals(taskExecutionStatus.get(taskId));
    }
    
    
    public void startDefaultBoot(){
    	List<HttpApi> httpList=HttpApi.dao.find("select * from "+HttpApi.TABLE_NAME+" where default_running='1' and enabled='1'");
    	for(HttpApi httpApi:httpList) {
    		startTask(httpApi.getId(),httpApi.getName(),"HTTP",httpApi.getFlow());
    	}
    	List<DataTask> dataTasks=DataTask.dao.find("select * from "+DataTask.TABLE_NAME+" where default_running='1' and enabled='1'");
    	for(DataTask dataTask:dataTasks) {
    		startTask(dataTask.getId());
    	}
    }
    
    public R<String> startTask(String taskName,String taskType,String taskId,String flowContent) {
        try {
        	startHTTP( taskId,taskName, taskType, flowContent);
            return R.ok();
        } catch (Exception e) {
            return R.failed(e.getMessage());
        }
    }
    
    
    /**
     * 启动任务调度
     * @param taskId 任务ID
     */
    public R<String> startTask(String taskId) {
        DataTask task = DataTask.dao.findById(taskId);
        if (task == null) {
            log.error("Task not found: {}", taskId);
            return R.failed("数据任务不存在.");
        }
        try {
        	startOLTP( taskId,task.getName(),"OLTP",task.getTrigger());
            return R.ok();
        } catch (Exception e) {
            return R.failed(e.getMessage());
        }
    }
    
    
    private void startOLTP(String taskId,String taskName,String taskType,String trigger) throws Exception{
    	start(taskId, taskName, taskType,trigger,null);
    }
    
    private void startHTTP(String taskId,String taskName,String taskType,String flowContent) throws Exception{
    	JSONObject flow= JSONObject.parseObject(flowContent);
    	if(flow==null || flow.isEmpty()) {
    		throw new Exception("flowContent数据解析成JSONObject为null.");
    	}
    	start(taskId, taskName, taskType,JSONObject.toJSONString(flow.getJSONObject("trigger")),flow);
    }
    
    /**
     * 启动任务调度
     * @param taskId 任务ID
     * @throws Exception 
     */
    private void start(String taskId,String taskName,String taskType,String trigger,JSONObject flow) throws Exception {

    	if(isRunning(taskId)) {
        	throw new Exception(String.format("%s 已运行中，无需重复启动.",taskId));
        }
    	
        JSONObject triggerConfig =JSONObject.parseObject(trigger);
    	if(triggerConfig==null || triggerConfig.isEmpty()) {
   		 	throw new Exception(String.format("%s 流程trigger配置为空.",taskId));
    	}
    	
        String triggerType = triggerConfig.getString("type");
        if(StrKit.equals("event", triggerType)) {
        	throw new Exception(String.format("%s 为事件触发，无需启动.",taskId));
        }
        
        try {
            
            String exec = triggerConfig.getString("exec");
            Runnable taskRunner = () -> {
            	DataLog dataLog=dataLogService.createDataLog(taskId, taskName, taskType);
            	// 如果任务正在执行，则跳过本次调度
                if (isTaskExecuting(taskId)) {
                    log.warn("{} is still executing, skip this schedule", taskName);
                    dataLogService
                    .buildUpdateDataLog(dataLog.getId())
                    .setWarning(1)
                    .setInfo(String.format("%s is still executing, skip this schedule", taskName))
                    .setCompleted("1")
                    .setEndTime(new Date(System.currentTimeMillis()))
                    .update();
                    return;
                }
                
                 dataLogService
                .buildUpdateDataLog(dataLog.getId())
                .setInfo(String.format("%s 开始执行", taskName))
                .update();
                // 标记任务开始执行
                taskExecutionStatus.put(taskId, true);
                try {
                	if(StrKit.equals("HTTP", taskType)) {
                		httpApiService.executeTask(dataLog.getId(),taskId,flow);
                	}else {
                		dataTaskService.executeTask(dataLog.getId(),taskId);
                	}
                } catch (Exception e) {
                    log.error("{} execution failed: {}", taskName, e);
                    dataLogService
                    .buildUpdateDataLog(dataLog.getId())
                    .setError(1)
                    .setInfo(String.format("%s execution failed.%s", taskName,e.getMessage()))
                    .update();
                } finally {
                    // 标记任务执行完成
                    taskExecutionStatus.put(taskId, false);
                    dataLogService
                    .buildUpdateDataLog(dataLog.getId())
                    .setCompleted("1")
                    .setEndTime(new Date(System.currentTimeMillis()))
                    .update();
                }
            };

            ScheduledFuture<?> future = null;
            
            switch (exec) {
                case "interval":
                    // 间隔执行
                    long interval = triggerConfig.getLongValue("interval");
                    String unit = triggerConfig.getString("unit");
                    TimeUnit timeUnit = parseTimeUnit(unit);
                    future = scheduler.scheduleAtFixedRate(taskRunner, 0, interval, timeUnit);
                    break;
                    
                case "monthly":
                    // 每月执行
                    int dayOfMonth = triggerConfig.getIntValue("dayOfMonth");
                    String monthlyTimeOfDay = triggerConfig.getString("timeOfDay"); // HH:mm:ss
                    String[] monthlyTimeParts = monthlyTimeOfDay.split(":");
                    int monthlyHour = Integer.parseInt(monthlyTimeParts[0]);
                    int monthlyMinute = Integer.parseInt(monthlyTimeParts[1]);
                    int monthlySecond = monthlyTimeParts.length > 2 ? Integer.parseInt(monthlyTimeParts[2]) : 0;
                    
                    long monthlyDelay = calculateMonthlyDelay(dayOfMonth, monthlyHour, monthlyMinute, monthlySecond);
                    future = scheduler.scheduleAtFixedRate(taskRunner, monthlyDelay,
                            TimeUnit.DAYS.toMillis(30), TimeUnit.MILLISECONDS); // 使用30天作为近似
                    break;
                    
                case "yearly":
                    // 每年执行
                    int month = triggerConfig.getIntValue("month"); // 1-12
                    int dayOfYear = triggerConfig.getIntValue("dayOfMonth");
                    String yearlyTimeOfDay = triggerConfig.getString("timeOfDay"); // HH:mm:ss
                    String[] yearlyTimeParts = yearlyTimeOfDay.split(":");
                    int yearlyHour = Integer.parseInt(yearlyTimeParts[0]);
                    int yearlyMinute = Integer.parseInt(yearlyTimeParts[1]);
                    int yearlySecond = yearlyTimeParts.length > 2 ? Integer.parseInt(yearlyTimeParts[2]) : 0;
                    
                    long yearlyDelay = calculateYearlyDelay(month, dayOfYear, yearlyHour, yearlyMinute, yearlySecond);
                    future = scheduler.scheduleAtFixedRate(taskRunner, yearlyDelay,
                            TimeUnit.DAYS.toMillis(365), TimeUnit.MILLISECONDS); // 使用365天作为近似
                    break;
                    
                case "cron":
                    // CRON表达式执行
                    String cronExpression = triggerConfig.getString("expression");
                    if (StrKit.notBlank(cronExpression) && CronExpression.isValidExpression(cronExpression)) {
                        CronExpression cron = CronExpression.parse(cronExpression);
                        LocalDateTime nextRun = cron.next(LocalDateTime.now());
                        while (nextRun != null) {
                            LocalDateTime currentNext = nextRun;
                            future = scheduler.schedule(() -> {
                                taskRunner.run();
                                scheduleNextCron(taskId, cron, taskRunner);
                            }, java.time.Duration.between(LocalDateTime.now(), currentNext).toMillis(), TimeUnit.MILLISECONDS);
                            nextRun = cron.next(currentNext);
                        }
                    }
                    break;
                    
                case "fixedTime":
                    // 固定时间点执行
                    String timeStr = triggerConfig.getString("time"); // HH:mm:ss
                    String[] fixedTimeParts = timeStr.split(":");
                    int fixedHour = Integer.parseInt(fixedTimeParts[0]);
                    int fixedMinute = Integer.parseInt(fixedTimeParts[1]);
                    int fixedSecond = fixedTimeParts.length > 2 ? Integer.parseInt(fixedTimeParts[2]) : 0;
                    
                    long initialDelay = calculateInitialDelay(fixedHour, fixedMinute, fixedSecond);
                    future = scheduler.scheduleAtFixedRate(taskRunner, initialDelay, 
                            TimeUnit.DAYS.toMillis(1), TimeUnit.MILLISECONDS);
                    break;
                    
                default:
                    log.error("Unknown trigger type: {}", taskName,exec);
                    throw new Exception(String.format("%s Unknown trigger type:%", taskName,exec));
            }
            
            if (future != null) {
                scheduledTasks.put(taskId, future);
                log.info("Task scheduled: {}", taskId);
            }else {
            	throw new Exception(String.format("%s 启动失败.", taskName));
            }
        } catch (Exception e) {
            log.error("Failed to schedule task: {}，Error:{}", taskName, e);
            throw new Exception(String.format("Failed to schedule task: %s，Error:%s", taskName, e.getMessage()));
        }
    }
    

	/**
     * 停止任务调度
     * @param taskId 任务ID
     */
    public void stopTask(String taskId) {
    	ScheduledFuture<?> future = scheduledTasks.remove(taskId);
        if (future != null) {
            future.cancel(false);
            // 清除任务执行状态
            taskExecutionStatus.remove(taskId);
            log.info("Task stopped: {}", taskId);
        }
    }
    
    /**
     * 解析时间单位
     */
    private TimeUnit parseTimeUnit(String unit) {
        switch (unit.toLowerCase()) {
            case "seconds": return TimeUnit.SECONDS;
            case "minutes": return TimeUnit.MINUTES;
            case "hours": return TimeUnit.HOURS;
            case "days": return TimeUnit.DAYS;
            default: return TimeUnit.MINUTES;
        }
    }
    
    /**
     * 计算到指定时间点的延迟
     */
    private long calculateInitialDelay(int hour, int minute, int second) {
        long now = System.currentTimeMillis();
        java.util.Calendar calendar = java.util.Calendar.getInstance();
        calendar.set(java.util.Calendar.HOUR_OF_DAY, hour);
        calendar.set(java.util.Calendar.MINUTE, minute);
        calendar.set(java.util.Calendar.SECOND, second);
        
        long scheduledTime = calendar.getTimeInMillis();
        if (scheduledTime <= now) {
            scheduledTime += TimeUnit.DAYS.toMillis(1);
        }
        
        return scheduledTime - now;
    }
    
    /**
     * 调度下一次CRON执行
     */
    private void scheduleNextCron(String taskId, CronExpression cron, Runnable taskRunner) {
        LocalDateTime nextRun = cron.next(LocalDateTime.now());
        if (nextRun != null) {
            ScheduledFuture<?> future = scheduler.schedule(() -> {
                taskRunner.run();
                scheduleNextCron(taskId, cron, taskRunner);
            }, java.time.Duration.between(LocalDateTime.now(), nextRun).toMillis(), TimeUnit.MILLISECONDS);
            scheduledTasks.put(taskId, future);
        }
    }

    /**
     * 计算到下一个月指定日期的延迟
     */
    private long calculateMonthlyDelay(int dayOfMonth, int hour, int minute, int second) {
        java.util.Calendar now = java.util.Calendar.getInstance();
        java.util.Calendar next = java.util.Calendar.getInstance();
        
        next.set(java.util.Calendar.DAY_OF_MONTH, dayOfMonth);
        next.set(java.util.Calendar.HOUR_OF_DAY, hour);
        next.set(java.util.Calendar.MINUTE, minute);
        next.set(java.util.Calendar.SECOND, second);
        next.set(java.util.Calendar.MILLISECOND, 0);
        
        if (next.before(now)) {
            next.add(java.util.Calendar.MONTH, 1);
        }
        
        return next.getTimeInMillis() - now.getTimeInMillis();
    }

    /**
     * 计算到下一年指定日期的延迟
     */
    private long calculateYearlyDelay(int month, int dayOfMonth, int hour, int minute, int second) {
        java.util.Calendar now = java.util.Calendar.getInstance();
        java.util.Calendar next = java.util.Calendar.getInstance();
        
        next.set(java.util.Calendar.MONTH, month - 1); // Calendar月份从0开始
        next.set(java.util.Calendar.DAY_OF_MONTH, dayOfMonth);
        next.set(java.util.Calendar.HOUR_OF_DAY, hour);
        next.set(java.util.Calendar.MINUTE, minute);
        next.set(java.util.Calendar.SECOND, second);
        next.set(java.util.Calendar.MILLISECOND, 0);
        
        if (next.before(now)) {
            next.add(java.util.Calendar.YEAR, 1);
        }
        
        return next.getTimeInMillis() - now.getTimeInMillis();
    }

    /**
     * 获取任务执行状态
     */
    public boolean getTaskExecutionStatus(String taskId) {
        return isTaskExecuting(taskId);
    }

	/**
     * 停止所有运行中的任务
     */
    public void stopAllBoot() {
        // 遍历并停止所有运行中的任务
        for (String taskId : scheduledTasks.keySet()) {
            stopTask(taskId);
            log.info("Stopped running task: {}", taskId);
        }
        
        // 清空调度任务映射
        scheduledTasks.clear();
        
        // 清理任务执行状态
        taskExecutionStatus.clear();
        
        log.info("All running tasks stopped successfully");
    }
    
}
